#include "mySerial.h"

#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/uart.h"
#include "driver/gpio.h"
#include "esp_log.h"

static const char *TAG = "mySerial";

#define PATTERN_CHR_NUM 3

#define U0_SD_BUF_SIZE (1024)
#define U0_RD_BUF_SIZE (1024)

#define U1_SD_BUF_SIZE (1024)
#define U1_RD_BUF_SIZE (1024)
static QueueHandle_t uart0_queue;
static QueueHandle_t uart1_queue;
#define U0_QUEUE_DEP 32
#define U1_QUEUE_DEP 32

static void uart0_event_task(void *pvParameters)
{
  uart_event_t event;
  size_t buffered_size;
  uint8_t *read_buf = (uint8_t *)malloc(U0_RD_BUF_SIZE+1);
  while(1)
  {
    // Waiting for UART event.
    if (xQueueReceive(uart0_queue, (void *)&event, portMAX_DELAY))
    {
      memset(read_buf, 0, U0_RD_BUF_SIZE+1);
      ESP_LOGI(pcTaskGetName(NULL), "uart[0] event:");
      switch (event.type)
      {
      case UART_DATA:
        uart_read_bytes(UART_NUM_0, read_buf, event.size, portMAX_DELAY);
        ESP_LOGI(pcTaskGetName(NULL), "[UART_DATA EVT]: %s", read_buf);
        break;
      case UART_PATTERN_DET:
        uart_get_buffered_data_len(UART_NUM_0, &buffered_size);
        int pos = uart_pattern_pop_pos(UART_NUM_0);
        ESP_LOGI(pcTaskGetName(NULL), "[UART PATTERN DETECTED] pos: %d, buffered size: %d", pos, buffered_size);
        if (pos == -1) // 若模式定位的队列满了，则无法定位pos，这里简单刷新输入即可
          uart_flush_input(UART_NUM_0);
        else
        {
          uart_read_bytes(UART_NUM_0, read_buf, pos, 100 / portTICK_PERIOD_MS);
          uint8_t pat[PATTERN_CHR_NUM + 1];
          memset(pat, 0, sizeof(pat));
          uart_read_bytes(UART_NUM_0, pat, PATTERN_CHR_NUM, 100 / portTICK_PERIOD_MS);
          ESP_LOGI(pcTaskGetName(NULL), "read data: %s", read_buf);
          ESP_LOGI(pcTaskGetName(NULL), "read pat : %s", pat);
        }
        break;
      // Others
      default:
        ESP_LOGI(pcTaskGetName(NULL), "uart event type: %d", event.type);
        break;
      }
    }
  }
  free(read_buf);
  read_buf = NULL;
  vTaskDelete(NULL);
}

static void uart1_event_task(void *pvParameters)
{
  uart_event_t event;
  size_t buffered_size;
  uint8_t *read_buf = (uint8_t *)malloc(U1_RD_BUF_SIZE+1);
  while(1)
  {
    // Waiting for UART event.
    if (xQueueReceive(uart1_queue, (void *)&event, portMAX_DELAY))
    {
      memset(read_buf, 0, U1_RD_BUF_SIZE+1);
      ESP_LOGI(pcTaskGetName(NULL), "uart[1] event:");
      switch (event.type)
      {
      case UART_DATA:
        uart_read_bytes(UART_NUM_1, read_buf, event.size, portMAX_DELAY);
        ESP_LOGI(pcTaskGetName(NULL), "[UART_DATA EVT]: %s", read_buf);
        break;
      case UART_PATTERN_DET:
        uart_get_buffered_data_len(UART_NUM_1, &buffered_size);
        int pos = uart_pattern_pop_pos(UART_NUM_1);
        ESP_LOGI(pcTaskGetName(NULL), "[UART PATTERN DETECTED] pos: %d, buffered size: %d", pos, buffered_size);
        if (pos == -1) // 若模式定位的队列满了，则无法定位pos，这里简单刷新输入即可
          uart_flush_input(UART_NUM_1);
        else
        {
          uart_read_bytes(UART_NUM_1, read_buf, pos, 100 / portTICK_PERIOD_MS);
          uint8_t pat[PATTERN_CHR_NUM + 1];
          memset(pat, 0, sizeof(pat));
          uart_read_bytes(UART_NUM_1, pat, PATTERN_CHR_NUM, 100 / portTICK_PERIOD_MS);
          ESP_LOGI(pcTaskGetName(NULL), "read data: %s", read_buf);
          ESP_LOGI(pcTaskGetName(NULL), "read pat : %s", pat);
        }
        break;
      // Others
      default:
        ESP_LOGI(pcTaskGetName(NULL), "uart event type: %d", event.type);
        break;
      }
    }
  }
  free(read_buf);
  read_buf = NULL;
  vTaskDelete(NULL);
}

void serial0_init()
{
  // uart 配置参数
  uart_config_t uart_config = {
      .baud_rate = 115200,
      .data_bits = UART_DATA_8_BITS,
      .parity = UART_PARITY_DISABLE,
      .stop_bits = UART_STOP_BITS_1,
      .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
      .source_clk = UART_SCLK_DEFAULT,
  };
  // Install UART driver, and get the queue.
  uart_driver_install(UART_NUM_0, U0_RD_BUF_SIZE, U0_SD_BUF_SIZE, U0_QUEUE_DEP, &uart0_queue, 0);
  uart_param_config(UART_NUM_0, &uart_config);

  // Set UART pins (using UART0 default pins ie no changes.)
  uart_set_pin(UART_NUM_0, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);

  // 设置串口指令模式检测，将“---”作为触发关键词
  uart_enable_pattern_det_baud_intr(UART_NUM_0, '-', PATTERN_CHR_NUM, 10, 0, 0);
  // 设置指令队列，可同时处理 queue_length 个指令
  uart_pattern_queue_reset(UART_NUM_0, U0_QUEUE_DEP);

  // 创建 uart 数据处理任务
  xTaskCreate(uart0_event_task, "uart0_event_task", 1024*2, NULL, 12, NULL);
}

void serial1_init()
{
  // uart 配置参数
  uart_config_t uart_config = {
      .baud_rate = 115200,
      .data_bits = UART_DATA_8_BITS,
      .parity = UART_PARITY_DISABLE,
      .stop_bits = UART_STOP_BITS_1,
      .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
      .source_clk = UART_SCLK_DEFAULT,
  };
  // Install UART driver, and get the queue.
  uart_driver_install(UART_NUM_1, U1_RD_BUF_SIZE, U1_SD_BUF_SIZE, U1_QUEUE_DEP, &uart1_queue, 0);
  uart_param_config(UART_NUM_1, &uart_config);

  // Set UART pins
  uart_set_pin(UART_NUM_1, GPIO_NUM_2, GPIO_NUM_4, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);

  // 设置串口指令模式检测，将“---”作为触发关键词
  uart_enable_pattern_det_baud_intr(UART_NUM_1, '-', PATTERN_CHR_NUM, 10, 0, 0);
  // 设置指令队列，可同时处理 queue_length 个指令
  uart_pattern_queue_reset(UART_NUM_1, U1_QUEUE_DEP);

  // 创建 uart 数据处理任务
  xTaskCreate(uart1_event_task, "uart1_event_task", 1024*2, NULL, 12, NULL);
}
